/**
 * Sensor Network Development Kit for 1-Wire Network (SeN)
 * Version : 0.1
 * Revision date : 2008-10-13
 * Author: Dubravko Penezic, dpenezic@gmail.com
 * 
 * Based on T. Bitson, SimpleWeather, HumiditySensor.java, 2007
 */

package owSensor;

import com.dalsemi.onewire.*;
import com.dalsemi.onewire.adapter.*;
import com.dalsemi.onewire.container.*;
import owLib.*;

/**
 * BaroSensor class implement method to read DS2438 and baro sensor MPX4115
 * Version : 0.1.1
 * Revision date : 2008-10-26
 * 
 * @author Dubravko Penezic, dpenezic@gmail.com
 *
 */

public class BaroSensor
{
  // calibration constants
  private final double PRESSURE_GAIN   = 2.277707;
  private final double PRESSURE_OFFSET = 89.563477;
  
  // class variables
  private DSPortAdapter adapter;
  private OneWireContainer26 baroDevice = null;
  private static boolean debugFlag = OWConf.debugFlag;
  private OWDevice device;
  private OWCommPath p;
 
  /** 
   * BaroSensor method configure class parameters and create soft link to 1-Wire device
   *  
   * @param adapter
   * @param device
   */  
  public BaroSensor(DSPortAdapter adapter, OWDevice device)
  {
	    this.adapter = adapter;
	    this.device = device;
	    this.p = new OWCommPath(this.adapter, this.device);
  
        // get instances of the 1-wire devices
        baroDevice = new OneWireContainer26(adapter, device.getDAddress());
  }
  
  
/**
 * getPressure method read pressure from MPX4115 baro sensor and return value of pressure in kPa , using gain and offset in calculation
 * 
 * @return kPa
 */
  public double getPressure()
  {
    double pressure;
    
    if (debugFlag)
    {
      System.out.print("Pressure: Device = " + baroDevice.getName());
      System.out.print("  ID = " + baroDevice.getAddressAsString() + "\n");
    }
    
    // activate path for this device
    p.activatePath();
    
    try
    {
      byte[] state = baroDevice.readDevice();
            
      // Read voltage on A to D output
      baroDevice.doADConvert(OneWireContainer26.CHANNEL_VAD, state);
      double Vad = baroDevice.getADVoltage(OneWireContainer26.CHANNEL_VAD, state);
            
      // apply calibration
      pressure = Vad * PRESSURE_GAIN + PRESSURE_OFFSET;
 
      if (debugFlag)
      {
        // Read Supply Voltage (for reference only)
        baroDevice.doADConvert(OneWireContainer26.CHANNEL_VDD, state);
        double Vdd = baroDevice.getADVoltage(OneWireContainer26.CHANNEL_VDD, state);

        System.out.println("Sensor Output  = " + Vad + " Volts");
        System.out.println("Supply Voltage = " + Vdd + " Volts");
        System.out.println("Scale Factor   = " + PRESSURE_GAIN);
        System.out.println("Offset         = " + PRESSURE_OFFSET);
        System.out.println("Baro Pressure  = " + pressure + " kPa\n");
      }
    }
    catch (OneWireException e)
    {
      System.out.println("Error Reading Baro Sensor: " + e);
      pressure = 0;
    }
    
    // deactivate path for this device
    p.deactivatePath();
    
    return pressure;
  }

/**
 * getTemperature method return temperature measure by DS2438 chip which is at bast in range of +-2C and may change with working
 * condition of chip ... use only if you must !
 * 
 * @return C
 */
  public float getTemperature()
  {
    float temperature = -999.9f;
    
    if (debugFlag)
    {
      System.out.print("Pressure: Device = " + baroDevice.getName());
      System.out.print("  ID = " + baroDevice.getAddressAsString() + "\n");
    }

    // deactivate path for ths device
    p.activatePath();
    
    try
    {
      byte[] state = baroDevice.readDevice();
      
      
      // Read temperature
      baroDevice.doTemperatureConvert(state);
      temperature = (float) baroDevice.getTemperature(state);
      
    }
    catch (OneWireException e)
    {
      System.out.println("Error Reading Baro Sensor: " + e);
      temperature = -999.9f;
    }
    
    // deactivate path for ths device
    p.deactivatePath();
    
    return temperature;
  }

/**
 * calibration method show data for calibrating HB baro boards according example from T.Bitson and HB baro calibration page
 * 
 * For calibration you must set JP1 jumper in position 1-2 (dont forget to set it back in normal position 3-2 after calibration), 
 * set variable calib in example code to true. Start example code (HBBarometer.java) and set resistor on board that voltage which is 
 * measured is same with "Must to be" value. 
 * 
 * @param altitude m
 */
  public void calibration(int altitude)
  {
	// min atmospheric pressure in kPa (28 inHg)
	double MIN_AP = 94.818892;
	// max atmospheric pressure in kPa (32 inHg)
	double MAX_AP = 108.364448;
    
    if (debugFlag)
    {
      System.out.print("Pressure: Device = " + baroDevice.getName());
      System.out.print("  ID = " + baroDevice.getAddressAsString() + "\n");
    }

    // activate the path for this device
    p.activatePath();
    
    try
    {
      byte[] state = baroDevice.readDevice();
      
      
      // Read A to D output
      baroDevice.doADConvert(OneWireContainer26.CHANNEL_VAD, state);
      double Vad = baroDevice.getADVoltage(OneWireContainer26.CHANNEL_VAD, state);
      
      
      // Read Supply Voltage (for reference)
      baroDevice.doADConvert(OneWireContainer26.CHANNEL_VDD, state);
      double Vdd = baroDevice.getADVoltage(OneWireContainer26.CHANNEL_VDD, state);
      
      double minSP = calcAltPress(MIN_AP, altitude);
      double maxSP = calcAltPress(MAX_AP, altitude);
      
      double minSV = calcPressVolt(minSP, Vdd);
      double maxSV = calcPressVolt(maxSP, Vdd);
      
      // Calibration Voltage from T.Bitson table (dont know way)
      double calV = minSV - 0.2;
      
      double minINA122V = (minSV-calV)*10;
      double maxINA122V = (maxSV-calV)*10;
      
      double pg = (MAX_AP - MIN_AP)/(maxINA122V - minINA122V);
      double po = MAX_AP - (pg*maxINA122V);
      
      System.out.println("========================================================================");
      System.out.println("I Messured ="+Vad+"V    Must to be ="+calV+"V");
      System.out.println("------------------------------------------------------------------------");      
      System.out.println("I PRESSURE_GAIN = "+pg+"     PRESSURE_OFFSET = "+po);
      // need to be set at this class 
      System.out.println("========================================================================\n\n");
      if (debugFlag)
      {
    	  System.out.println("- Info -----------------------------------------------------------------");
          System.out.println("I Sensor Vad="+Vad+"V    Vdd="+Vdd+"V");
          System.out.println("I min Pressure = "+MIN_AP+" kPa     max Pressure = "+MAX_AP+" kPa");
          System.out.println("I min Alt Pressure = "+minSP+" kPa    max Alt Pressure = "+maxSP+" kPa");
          System.out.println("I min Sensor Voltage = "+minSV+" V    max Sensor Voltage = "+maxSV+" V");
          System.out.println("I min INA122 Voltage = "+minINA122V+" V    max INA122 Voltage = "+maxINA122V+" V");      
          System.out.println("------------------------------------------------------------------------");
      }
      
    }
    catch (OneWireException e)
    {
      System.out.println("Error Reading Baro Sensor: " + e);
    }
    
    // deactivate the path for this device
    p.deactivatePath();
    
  }

/**
 * calcAltPress method calculate pressure on some altitude for initial pressure on see level
 * 
 *  http://www.srh.noaa.gov/elp/wxcalc/formulas/stationPressure.pdf
 * 
 * @param preassure kPa
 * @param alt m
 * @return kPa
 */
  private double calcAltPress(double pressure, double alt){
	  
	  return pressure*Math.pow(((288-0.0065*alt)/288), 5.2561);
	  
  }

/**
 * calcPressVolt method calculate voltage on output of MPX4115 sensor according pressure and volts on supply line (Vs)
 * 
 *   http://www.geocities.com/SiliconValley/Orchard/6633/MPX4115.pdf
 *   
 * @param preassure in kPa
 * @param Vs Volts
 * @return Volts
 */
  private double calcPressVolt(double pressure, double Vs){
	  
	  return Vs*(0.009*pressure-0.095);
	  
  }
}